import axios from 'axios'
import Vue from '@/main'

class IRequest {
  // 常量
  BEFORE_SEND = 'beforeSend'
  AFTER_SEND = 'afterSend'
  FAIL = 'fail'

  // 中间件
  middlerware = {
    // 接口发送前
    beforeSend: () => {},
    // 接口发送后
    afterSend: () => {},
    // 请求失败
    fail: () => {}
  }

  /**
   * 加载接口请求中间件
   * @param { Array } middlerwares 中间件数组
   * @param { Array } type 插入类型
   */
  use (middlerwares, type) {
    // 如果当前没有传入中间件
    if (!middlerwares) {
      throw new Error('请传入中间件')
    }
    // 记录中间件是否是方法
    let isFunction = true
    // 判断中间件每一个类型
    middlerwares.forEach(item => {
      isFunction = isFunction && (item instanceof Function)
    })
    // 中间件如果不是函数
    if (!isFunction) {
      throw new Error('中间件必须是函数，请检查传入的中间件类型')
    }
    // 根据类型处理中间件
    switch (type) {
      case this.BEFORE_SEND: // 接口发送前
        this.middlerware.beforeSend = this.compose(middlerwares)
        break
      case this.AFTER_SEND: // 接口发送后
        this.middlerware.afterSend = this.compose(middlerwares)
        break
      case this.FAIL: // 接口发送失败
        this.middlerware.fail = this.compose(middlerwares)
        break
    }
  }

  /**
   * 集成中间件
   * @param { Array } middlerwares 中间件几何
   */
  compose (middlerwares, next) {
    return params => {
      const dispatch = i => {
        // 当前待执行的方法
        let fn = middlerwares[i]
        // 下一个方法
        if (i === middlerwares.length) {
          // 如果有中间件全部执行完成后的方法
          fn = next
        }
        // 如果当前没有方法
        if (!fn) {
          return
        }
        fn(params, dispatch.bind(null, i + 1))
      }
      return dispatch(0)
    }
  }

  /**
   * 请求接口
   * @param { Object } options 请求参数
   */
  async request (options) {
    // 开始执行请求前中间件
    await this.middlerware.beforeSend(options)
    // 请求接口
    const resp = await axios(options).catch(async error => {
      await this.middlerware.fail(error)
    })
    // 关闭弹框
    Vue.$loading.close()
    // 开始执行请求后中间件
    await this.middlerware.afterSend(resp)
    return resp.data
  }
}

export default new IRequest()
